﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace _2图像灰度化
    /////////////////////////////////采用加权平均值法  ret=(int)(curColor.R*0.299+curColor.G*0.587+curColor.B*0.114);
{
    public partial class Form1 : Form
    {
        private string cur;//文件位置
        private System.Drawing.Bitmap curBitmap;//图像对象
        private HiPerfTimer myTimer;

        public Form1()
        {
            InitializeComponent();
            myTimer = new HiPerfTimer();
        }

        private void Form1_Load(object sender, EventArgs e)
        {

        }

        private void open_Click(object sender, EventArgs e)
        {
            OpenFileDialog od = new OpenFileDialog();
            od.Filter = "所有图像文件|*.bmp;*.pcx;*.jpg;*.gif"+
                "*.tif;*.ico;*.dxf;*.cgm;*.cdr|"+
                "位图(*.bmp;*.jpg;*.png;...)|*.bmp;*.jpg;*.png";
            od.Title = "打开图像文件";
            od.ShowHelp = true;
            if(od.ShowDialog()==DialogResult.OK)
            {
                cur = od.FileName;
                try
                {
                    curBitmap = (Bitmap)Image.FromFile(cur);
                }
                catch(Exception ex)
                {
                    MessageBox.Show(ex.Message);
                }
                Console.WriteLine(cur);
                Console.WriteLine(curBitmap);
            }
            
            Invalidate();
        }

        private void close_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        private void save_Click(object sender, EventArgs e)
        {
            if (curBitmap == null)
            {
                return;
            }
            SaveFileDialog sd = new SaveFileDialog();
            sd.Title = "保存为";
            sd.OverwritePrompt = true;
            sd.Filter = "bmp文件(*.bmp)|*.bmp|"+
                "gif文件(*.gif)|*.gif"+
                "jpeg文件(*..jpg)|*.jpg"+
                "png文件(*.png)|*.png";
            sd.ShowHelp = true;
            if(sd.ShowDialog()==DialogResult.OK)
            {
                string src = sd.FileName;
                string ext = src.Remove(0,src.Length-3);
                switch(ext)
                {
                    case "bmp":
                        curBitmap.Save(src,System.Drawing.Imaging.ImageFormat.Bmp);break;
                    case "jpp":
                        curBitmap.Save(src, System.Drawing.Imaging.ImageFormat.Jpeg); break;
                    case "gif":
                        curBitmap.Save(src, System.Drawing.Imaging.ImageFormat.Gif); break;
                    case "tif":
                        curBitmap.Save(src, System.Drawing.Imaging.ImageFormat.Tiff); break;
                    case "png":
                        curBitmap.Save(src, System.Drawing.Imaging.ImageFormat.Png); break;
                    default:
                        break;
                }
            }
        }

        private void Form1_Paint(object sender, PaintEventArgs e)
        {
            Graphics g = e.Graphics;
            if (curBitmap != null)
            {
                g.DrawImage(curBitmap,160,20,curBitmap.Width,curBitmap.Height);
            }
        }

        private void pixel_Click(object sender, EventArgs e)
        {
            if (curBitmap != null)
            {
                myTimer.Start();

                Color curColor;
                int ret;
                for (int i = 0; i < curBitmap.Width; i++)
                {
                    for (int j = 0; j < curBitmap.Height;j++ )
                    {
                        curColor = curBitmap.GetPixel(i,j);
                        ret=(int)(curColor.R*0.299+curColor.G*0.587+curColor.B*0.114);
                        curBitmap.SetPixel(i,j,Color.FromArgb(ret,ret,ret));
                    }
                }

                myTimer.Stop();
                timeBox.Text = myTimer.Duration.ToString("####.##") + "毫秒";

                Invalidate();
            }
        }

        private void memory_Click(object sender, EventArgs e)
        {
            if (curBitmap != null)
            {
                myTimer.Start();

                Rectangle rect = new Rectangle(0,0,curBitmap.Width,curBitmap.Height);
                System.Drawing.Imaging.BitmapData bmpData = curBitmap.LockBits(
                    rect,System.Drawing.Imaging.ImageLockMode.ReadWrite,curBitmap.PixelFormat);
                IntPtr ptr = bmpData.Scan0;

                /*
                #region 任意大小的24位彩色图像

                int bytes = bmpData.Stride * bmpData.Height;///////////////////////////////
                byte[] rgbValues = new byte[bytes];
                System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValues, 0, bytes);

                double colorTemp = 0;
                for (int i = 0; i < bmpData.Height; i ++)
                {
                    for (int j = 0; j < bmpData.Width*3; j++)//zhe li you wenti 
                    {                       
                            colorTemp = rgbValues[i * bmpData.Stride + j + 2] * 0.299 +
                                rgbValues[i * bmpData.Stride + j + 1] * 0.587 +
                                rgbValues[i * bmpData.Stride + j] * 0.114;
                            rgbValues[i * bmpData.Stride + j + 2] =
                                rgbValues[i * bmpData.Stride + j + 1] =
                                rgbValues[i * bmpData.Stride + j] = (byte)colorTemp;                        
                    }                        
                }
                System.Runtime.InteropServices.Marshal.Copy(rgbValues, 0, ptr, bytes);

                curBitmap.UnlockBits(bmpData);///////////////////////////////////////////////////

                #endregion
                 */

                #region  没有未用空间
                          
                //24位bmp位图字节数   512*512 没有未用空间
                int bytes = curBitmap.Width * curBitmap.Height * 3;
                byte[] rgbValues=new byte[bytes];
                System.Runtime.InteropServices.Marshal.Copy(ptr,rgbValues,0,bytes);

                double colorTemp = 0;
                for (int i = 0; i < rgbValues.Length; i += 3)
                {
                    colorTemp = rgbValues[i + 2] * 0.299 + rgbValues[i + 1] * 0.587 + rgbValues[i] * 0.114;
                    rgbValues[i + 2] = rgbValues[i + 1] = rgbValues[i ] = (byte)colorTemp;
                }
                System.Runtime.InteropServices.Marshal.Copy(rgbValues, 0,ptr, bytes);

                curBitmap.UnlockBits(bmpData);
                
                #endregion

                myTimer.Stop();
                timeBox.Text = myTimer.Duration.ToString("####.##") + "毫秒";

                Invalidate(); 
               
            }
        }

        private void pointer_Click(object sender, EventArgs e)//该段代码适用于所有24位图像
        {
            if (curBitmap != null)
            {
                myTimer.Start();

                Rectangle rect = new Rectangle(0, 0, curBitmap.Width, curBitmap.Height);
                System.Drawing.Imaging.BitmapData bmpData = curBitmap.LockBits(
                    rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, curBitmap.PixelFormat);
                byte temp = 0;

                //启动不安全模式
                unsafe
                {
                    byte* ptr=(byte*)(bmpData.Scan0);//得到首地址
                    for (int i = 0; i < bmpData.Height; i++)
                    {
                        for (int j = 0; j < bmpData.Width ; j++)
                        {
                            temp = (byte)(0.299 * ptr[2] + 0.587 * ptr[1] + 0.114 * ptr[0]);
                            ptr[2] = ptr[1] = ptr[0] = temp;
                            ptr += 3;
                        }
                        ptr += bmpData.Stride - bmpData.Width * 3;
                    }
                }

                curBitmap.UnlockBits(bmpData);

                myTimer.Stop();
                timeBox.Text = myTimer.Duration.ToString("####.##") + "毫秒";
                Invalidate();
            }//endif
        }

        private void min_Click(object sender, EventArgs e)/////////最小值法，据说识别率高，图片变黑
        {
            if (curBitmap != null)
            {
                myTimer.Start();

                Rectangle rect = new Rectangle(0,0,curBitmap.Width,curBitmap.Height);
                System.Drawing.Imaging.BitmapData bmpData = curBitmap.LockBits(
                    rect,System.Drawing.Imaging.ImageLockMode.ReadWrite,curBitmap.PixelFormat);
                IntPtr ptr = bmpData.Scan0;

                #region 24位彩色图像

                int bytes = curBitmap.Width * curBitmap.Height * 3;
                byte[] rgbValues = new byte[bytes];
                System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValues, 0, bytes);

                double colorTemp = 0;
                for (int i = 0; i < rgbValues.Length; i += 3)
                {
                    //colorTemp = rgbValues[i + 2] * 0.299 + rgbValues[i + 1] * 0.587 + rgbValues[i] * 0.114;
                    colorTemp = rgbValues[i + 2];
                    if (colorTemp > rgbValues[i + 1])
                    {
                        colorTemp = rgbValues[i + 1];
                    }
                    if (colorTemp > rgbValues[i ])
                    {
                        colorTemp = rgbValues[i ];
                    }
                    rgbValues[i + 2] = rgbValues[i + 1] = rgbValues[i] = (byte)colorTemp;
                }
                System.Runtime.InteropServices.Marshal.Copy(rgbValues, 0, ptr, bytes);

                curBitmap.UnlockBits(bmpData);///////////////////////////////////////////////////

                #endregion
                myTimer.Stop();
                timeBox.Text = myTimer.Duration.ToString("####.##") + "毫秒";

                Invalidate();

            }
        }

        private void max_Click(object sender, EventArgs e)///////////最大值法，图片变白
        {
            if (curBitmap != null)
            {
                myTimer.Start();

                Rectangle rect = new Rectangle(0, 0, curBitmap.Width, curBitmap.Height);
                System.Drawing.Imaging.BitmapData bmpData = curBitmap.LockBits(
                    rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, curBitmap.PixelFormat);
                IntPtr ptr = bmpData.Scan0;

                #region 24位彩色图像

                int bytes = curBitmap.Width * curBitmap.Height * 3;
                byte[] rgbValues = new byte[bytes];
                System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValues, 0, bytes);

                double colorTemp = 0;
                for (int i = 0; i < rgbValues.Length; i += 3)
                {
                    //colorTemp = rgbValues[i + 2] * 0.299 + rgbValues[i + 1] * 0.587 + rgbValues[i] * 0.114;
                    colorTemp = rgbValues[i + 2];
                    if (colorTemp < rgbValues[i + 1])
                    {
                        colorTemp = rgbValues[i + 1];
                    }
                    if (colorTemp < rgbValues[i])
                    {
                        colorTemp = rgbValues[i];
                    }
                    rgbValues[i + 2] = rgbValues[i + 1] = rgbValues[i] = (byte)colorTemp;
                }
                System.Runtime.InteropServices.Marshal.Copy(rgbValues, 0, ptr, bytes);

                curBitmap.UnlockBits(bmpData);///////////////////////////////////////////////////

                #endregion
                myTimer.Stop();
                timeBox.Text = myTimer.Duration.ToString("####.##") + "毫秒";

                Invalidate();

            }
        }

        private void er值化127_Click(object sender, EventArgs e)//以127为阀值
        {
            if (curBitmap != null)//对灰度化后的图像进行处理
            {
                myTimer.Start();

                Rectangle rect = new Rectangle(0, 0, curBitmap.Width, curBitmap.Height);
                System.Drawing.Imaging.BitmapData bmpData = curBitmap.LockBits(
                    rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, curBitmap.PixelFormat);
               // byte temp = 0;

                //启动不安全模式
                unsafe
                {
                    byte* ptr = (byte*)(bmpData.Scan0);//得到首地址
                    for (int i = 0; i < bmpData.Height; i++)
                    {
                        for (int j = 0; j < bmpData.Width; j++)
                        {
                            if(ptr[0]>127)
                                ptr[2] = ptr[1] = ptr[0] = 255;
                            else
                                ptr[2] = ptr[1] = ptr[0] = 0;
                            ptr += 3;
                        }
                        ptr += bmpData.Stride - bmpData.Width * 3;
                    }
                }

                curBitmap.UnlockBits(bmpData);

                myTimer.Stop();
                timeBox.Text = myTimer.Duration.ToString("####.##") + "毫秒";
                Invalidate();
            }//endif
        }

        private void avgErzhihua_Click(object sender, EventArgs e)
        //灰度化后二值化,可能导致部分对象像素或者背景像素丢失
        
        {
            if (curBitmap != null)
            {
                myTimer.Start();

                Rectangle rect = new Rectangle(0, 0, curBitmap.Width, curBitmap.Height);
                System.Drawing.Imaging.BitmapData bmpData = curBitmap.LockBits(
                    rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, curBitmap.PixelFormat);
               // byte temp = 0;

                //启动不安全模式
                unsafe
                {
                    byte* ptr = (byte*)(bmpData.Scan0);//得到首地址

                    int avg;//////////////////////////////计算灰度化平均值
                    int sum = 0;
                    int num = 0;
                    for (int i = 0; i < bmpData.Height; i++)
                    {
                        for (int j = 0; j < bmpData.Width; j++)
                        {
                            sum += ptr[0];
                            num++;
                            ptr += 3;
                        }
                        ptr += bmpData.Stride - bmpData.Width * 3;//下一行
                    }

                    avg =(int) sum / num;

                    //width*每个像素所含字节数+未用空间=stride
                    //height行数

                    //Console.WriteLine(avg);
                    //Console.ReadKey();

                    ptr = (byte*)(bmpData.Scan0);
                    for (int i = 0; i < bmpData.Height; i++)
                    {
                        for (int j = 0; j < bmpData.Width; j++)
                        {
                            if (ptr[0] > avg)
                                ptr[2] = ptr[1] = ptr[0] = 255;
                            else
                                ptr[2] = ptr[1] = ptr[0] = 0;
                            ptr += 3;
                        }
                        ptr += bmpData.Stride - bmpData.Width * 3;
                    }
                }

                curBitmap.UnlockBits(bmpData);

                myTimer.Stop();
                timeBox.Text = myTimer.Duration.ToString("####.##") + "毫秒";
                Invalidate();
            }//endif
        }

        private void Bernsen_Click(object sender, EventArgs e)//Bernsen方法有问题
        {
            if (curBitmap != null)
            {
                myTimer.Start();

                Rectangle rect = new Rectangle(0, 0, curBitmap.Width, curBitmap.Height);
                System.Drawing.Imaging.BitmapData bmpData = curBitmap.LockBits(
                    rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, curBitmap.PixelFormat);
               // byte temp = 0;

                //启动不安全模式
                unsafe
                {
                    byte* ptr = (byte*)(bmpData.Scan0);//得到首地址
                    
                    int[,] extend = new int[bmpData.Height+2
                        ,bmpData.Width+2];//扩展数组 

                    for (int i = 0; i < bmpData.Height; i++)//对数组初始化
                    {
                        for (int j = 0; j < bmpData.Width; j++)
                        {
                            extend[i+1,j+1]= ptr[2];
                            ptr += 3;
                        }
                        ptr += bmpData.Stride - bmpData.Width * 3;//下一行
                    }

                    #region 四周数组赋值
                    
                    for (int i = 1; i < bmpData.Width+1 ; i++)//初始化第一行，除了2端的2个
                    {
                        extend[0,i]=extend[2,i];//以第一行为对称轴进行填充
                    }
                    for (int i = 1; i < bmpData.Width + 1; i++)//初始化最后一行
                    {
                        extend[bmpData.Height + 1, i] = extend[bmpData.Height -1, i];
                    }
                    for (int i = 1; i < bmpData.Height + 1; i++)//初始化第一列
                    {
                        extend[i, 0] = extend[i, 2];
                    }
                    for (int i = 1; i < bmpData.Height + 1; i++)//初始化最后一列
                    {
                        extend[i, bmpData.Width + 1] = extend[i, bmpData.Width - 1];
                    }
                    //填充四个角
                    extend[0,0]=extend[1,1];
                    extend[0, bmpData.Width + 1] = extend[1, bmpData.Width ];
                    extend[bmpData.Height + 1, 0] = extend[bmpData.Height, 1];
                    extend[bmpData.Height + 1, bmpData.Width + 1] = extend[bmpData.Height, bmpData.Width];
                    #endregion

                    double avg=0;//////////////////////////////计算灰度化3*3表格（最大+最小）/2的平均值                
                    int max1, min1;
                    //width*每个像素所含字节数+未用空间=stride
                    //height行数
                    
                    ptr = (byte*)(bmpData.Scan0);
                    for (int i = 0; i < bmpData.Height; i++)
                    {
                        for (int j = 0; j < bmpData.Width; j++)
                        {
                            max1 = maxFunction(extend, i + 1, j + 1);
                            min1 = minFunction(extend, i + 1, j + 1);
                            avg =(max1+min1)*0.5;
                            if (ptr[2] > avg)
                                ptr[2] = ptr[1] = ptr[0] = 255;
                            else
                                ptr[2] = ptr[1] = ptr[0] = 0;
                            ptr += 3;
                        }
                        ptr += bmpData.Stride - bmpData.Width * 3;
                    }
                }

                curBitmap.UnlockBits(bmpData);

                myTimer.Stop();
                timeBox.Text = myTimer.Duration.ToString("####.##") + "毫秒";
                Invalidate();
            }//endif

        }
        private  int maxFunction(int[,] a,int m ,int n)//3*3表格中找到最大值
        {
            int max = a[m,n];
            for (int i =-1; i < 2;i++ )
            {
                for (int j = -1; j < 2; j++)
                {
                    if (max < a[m + i,n + j])
                        max = a[m + i,n + j];
                }
            }
            return max;
        }
        private int minFunction(int[,] a, int m, int n)//3*3表格中找到最小值
        {
            int min = a[m,n];
            for (int i = -1; i < 2; i++)
            {
                for (int j = -1; j < 2; j++)
                {
                    if (min > a[m + i,n + j])
                        min = a[m + i,n + j];
                }
            }
            return min;
        }

        private void oust二值化_Click(object sender, EventArgs e)
        {

        }
        unsafe private int GetthreshValue(Bitmap img)
        {
            System.Drawing.Imaging.BitmapData bd = img.LockBits(new Rectangle(0, 0, img.Width, img.Height), ImageLockMode.WriteOnly, img.PixelFormat);
            byte* pt = (byte*)bd.Scan0;
            int[] pixelNum = new int[256];
            byte color;
            byte* pline;
            int n, n1, n2;
            int total;
            double m1, m2, sum, csum, fmax, sb;
            int k, t, q;
            int threshValue = 1;
            int step = 1;
            switch (img.PixelFormat)
            {
                case System.Drawing.Imaging.PixelFormat.Format24bppRgb:
                    step = 3;
                    break;
                case System.Drawing.Imaging.PixelFormat.Format32bppRgb:
                    step = 4;
                    break;
                case System.Drawing.Imaging.PixelFormat.Format8bppIndexed:
                    step = 1;
                    break;

            }
            //生成直方图
            for (int i = 0; i < img.Height; i++)
            {
                pline = pt + i * bd.Stride;
                for (int j = 0; j < img.Width; j++)
                {
                    color = *(pline + j * step);
                    pixelNum[color]++;
                }
            }
            //直方图平滑化
            for (k = 0; k <= 255; k++)
            {
                total = 0;
                for (t = -2; t <= 2; t++)
                {
                    q = k + t;
                    if (q < 0)
                    {
                        q = 0;
                    }
                    if (q > 255)
                    {
                        q = 255;
                    }
                    total = total + pixelNum[q];
                }
                pixelNum[k] = (int)((float)total / 5.0 + 0.5);
            }
            //求
            csum = 0;
            sum = csum;
            n = 0;
            for (k = 0; k <= 255; k++)
            {
                sum += (double)k * (double)pixelNum[k];
                n += pixelNum[k];
            }
            fmax = -1.0;
            n1 = 0;
            for (k = 0; k < 255; k++)
            {
                n1 += pixelNum[k];
                if (n1 == 0)
                {
                    continue;
                }
                n2 = n - n1;
                if (n2 == 0)
                {
                    break;
                }
                csum += (double)k * pixelNum[k];
                m1 = csum / n1;
                m2 = (sum - csum) / n2;
                sb = (double)n1 * (double)n2 * (m1 - m2) * (m1 - m2);
                if (sb > fmax)
                {
                    fmax = sb;
                    threshValue = k;
                }
            }
            img.UnlockBits(bd);

            return threshValue;
        }

    }
}
